using System;
using System.Collections.Generic;
using System.Linq;
using Web.App.Infrastructure.Extensions;
using Webshop20.Domain.Common;
using Webshop20.Domain.Common.Exceptions;
using Webshop20.Domain.Shared.Products.Core;
using Web.App.Infrastructure.ApplicationMessages.Implementation;

namespace Webshop20.Domain.Catalog.Core
{
    [Serializable]
    public class ShoppingCart : Entity
    {

        private const int ONE_ITEM = 1;

        private IList<ShoppingCartItem> shoppingCartItems  { get; set;}
        private IList<SavedItem> savedItems { get; set; }

        public virtual int TotalItemsCount
        {
            get { throw new NotImplementedException();}
        }

        public virtual IEnumerable<ShoppingCartItem> CartItems
        {
            get { return shoppingCartItems; }
        }


        public virtual IEnumerable<SavedItem> SavedItems
        {
            get { return savedItems; }
        }

        public virtual Product LastAddedProduct
        {
            get { throw new NotImplementedException();}
        }

        public ShoppingCart()
        {
            shoppingCartItems = new List<ShoppingCartItem>();
            savedItems = new List<SavedItem>();
        }

        public virtual ShoppingCartItem AddProduct(Product product, DateTime addedAt)
        {
            return AddProduct(product, ONE_ITEM, addedAt);
        }

        public virtual ShoppingCartItem AddProduct(Product product, int quantity, DateTime addedAt)
        {
            var cartItem = shoppingCartItems.Where(item => item.Product.Id == product.Id).FirstOrDefault();
            
            if(cartItem.Exists())
            {
                shoppingCartItems.Remove(cartItem);
                quantity += cartItem.Quantity; 
            }

            var newShoppingCartItem = new ShoppingCartItem(quantity, product, addedAt);
            shoppingCartItems.Add(newShoppingCartItem);

            return newShoppingCartItem;
        }

        public virtual void RemoveCartItemFor(Product product)
        {
            var cartItemToRemove = shoppingCartItems.Where(item => item.Product.Id == product.Id).FirstOrDefault();
            if (cartItemToRemove.Exists())
                shoppingCartItems.Remove(cartItemToRemove);
        }

        public virtual void MergeWith(ShoppingCart cart)
        {
            foreach (var cartItemToMerge in cart.CartItems)
            {
                AddProduct(cartItemToMerge.Product, cartItemToMerge.Quantity, cartItemToMerge.AddedAt);
            }   
        }

        public virtual  void ChangeQuantity(Product product, int newQuantity)
        {
            if(newQuantity < 0)
                throw new DomainException(new DomainMessage("ShoppingCart", "ChangeQuantity", "NO_NEGATIVE_QUANTITIES_ALLOWED"));

            var cartItem = shoppingCartItems.Where(item => item.Product.Id == product.Id).FirstOrDefault();

            if (cartItem.Exists())
            {
                shoppingCartItems.Remove(cartItem);
                shoppingCartItems.Add(new ShoppingCartItem(newQuantity, product, cartItem.AddedAt));
            }
        }

        public virtual void Clear()
        {
            shoppingCartItems.Clear();
        }

        public virtual void AddProductToSavedItemList(Product product)
        {
            var savedItem = savedItems.Where(item => item.Product.Id == product.Id).FirstOrDefault();

            if(!savedItem.Exists())
                savedItems.Add(new SavedItem(product));
        }

        public virtual void RemoveProductToSavedItemList(Product product)
        {
            var savedItem = savedItems.Where(item => item.Product.Id == product.Id).FirstOrDefault();

            if (savedItem.Exists())
                savedItems.Remove(savedItem);
        }

        public virtual void MoveProductFromCartItemListToSavedItemList(Product product)
        {
            var cartItem = shoppingCartItems.Where(item => item.Product.Id == product.Id).FirstOrDefault();

            if (cartItem.Exists())
            {
                shoppingCartItems.Remove(cartItem);
                savedItems.Add(new SavedItem(product));
            }
        }


        public virtual decimal CalculateTotal(ISalesTax salesTax, DateTime calculationDate)
        {
            return shoppingCartItems.Sum(item => item.Calculate(salesTax, calculationDate));
        }
    }
}